package com.zrkizzy.module.system.service.resource;

import com.zrkizzy.common.core.utils.IdUtil;
import com.zrkizzy.common.models.domain.system.resource.Resource;
import com.zrkizzy.system.facade.service.resource.IApiScanService;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * API接口扫描
 *
 * @author zhangrongkang
 * @since 2023/11/13
 */
@Slf4j
@Service
public class ApiScanServiceImpl implements IApiScanService {

    @Autowired
    WebApplicationContext webApplicationContext;

    @Autowired
    private IdUtil idUtil;

    /**
     * 不需要认证路径：public
     */
    private static final String NO_AUTHENTICATION_PUBLIC = "/public";

    /**
     * 不需要认证的路径：test
     */
    private static final String NO_AUTHENTICATION_TEST = "/test";

    /**
     * 获取权限集合
     *
     * @return 所有请求权限集合
     */
    @Override
    public List<Resource> listSecurityApi() {
        // 定义返回结果
        List<Resource> result = new ArrayList<>();

        RequestMappingHandlerMapping mapping = webApplicationContext.getBean("requestMappingHandlerMapping",RequestMappingHandlerMapping.class);
        // 拿到Handler适配器中的所有方法
        Map<RequestMappingInfo, HandlerMethod> methodMap = mapping.getHandlerMethods();

        // 遍历所有方法
        for (Map.Entry<RequestMappingInfo, HandlerMethod> methodEntry : methodMap.entrySet()) {
            // 处理器方法
            HandlerMethod handlerMethod = methodEntry.getValue();
            // 请求映射信息
            RequestMappingInfo requestMappingInfo = methodEntry.getKey();

            Resource resource = new Resource();
            // 设置当前请求资源参数信息
            if (!setResourceAttribute(resource, handlerMethod, requestMappingInfo)) {
                continue;
            }

            // 保存当前遍历接口信息
            result.add(resource);
        }
        return result;
    }

    /**
     * 设置当前资源对象信息
     *
     * @param resource 资源实体类
     * @param handlerMethod 请求处理器
     * @param requestMappingInfo 请求映射信息
     * @return 当前请求是否需要记录
     */
    private Boolean setResourceAttribute(Resource resource, HandlerMethod handlerMethod, RequestMappingInfo requestMappingInfo) {
        // 设置ID
        resource.setId(idUtil.nextId());
        // 获取请求方法类型
        RequestMethodsRequestCondition methodsCondition = requestMappingInfo.getMethodsCondition();
        String methodType = methodsCondition.getMethods().toString();
        // 设置请求类型信息
        resource.setMethod(methodType.substring(1, methodType.length() - 1));

        // 设置请求URL信息
        Set<String> patternValues = requestMappingInfo.getPatternValues();
        // 获取到所有请求URL
        String url = String.join("", patternValues);
        // 判断当前是否合法
        if (StringUtils.hasLength(url) && (url.startsWith(NO_AUTHENTICATION_PUBLIC) || url.startsWith(NO_AUTHENTICATION_TEST))) {
            return Boolean.FALSE;
        }
        resource.setUrl(url);

        // 设置资源名称和资源描述信息
        Method method = handlerMethod.getMethod();
        Operation operation = method.getAnnotation(Operation.class);
        if (null == operation) {
            return Boolean.FALSE;
        }
        resource.setName(operation.summary());
        resource.setDescription(operation.summary());

        // 设置创建时间和更新时间
        resource.setCreateTime(LocalDateTime.now());

        return Boolean.TRUE;
    }

}
